- Make 'macroexp' work with locally defined macros (i.e: through 'let'). This
  probably needs a new opcode that stores the macros/aliases into the dynamic
  frame, and then have the macroexpand function look into the preceeding let
  bindings to see if there's any of them.

- Don't use a reference to 'stkend' in the bytecode evaluation function.
  Instead, use a simple variable and store in the interpreter before a call
  to another function is made, and restore it afterwards. Be careful with
  methods that implicitly manipulate the member 'stkend', like 'pop' et al.

- There are too many hash table implementations around. Specifically, all
  the ad-hoc open addressing tables should be condensed into a single type,
  with template specializations.

- Allow macros to take an optional parameter, '[:env]', that contains the
  lexical environment at the time of the call. This would be a simple
  list with symbols that callers could query with 'memq' or the like,
  in order to know if a symbol is locally or globaly bound.

- When setting a global symbol, we shouldn't just modify its value, but rather
  intern a new one with the same name and the updated value, in case we are
  executing in a different package.

- Remove the first element in the function frame (aka 'env'), because it's
  already being accesed without it being referenced.

- Instead of using a pair of <object*, int> to specify arguments in
  native functions, construct an object that encapsulates those details.
  This will allow us to be robust against stack reallocations as well.

- Don't use frame pointers, and instead make any access to local variables
  be relative to 'interp->stkend'. This may mean different offsets for the
  same local at different points of execution, but it frees up a register
  in the AOT compiler for whatever we may need it.
